package org.monster.context.servlet;

import org.monster.context.core.parameter.HttpResponse;
import org.monster.context.core.parameter.HttpResponseFacade;
import org.monster.context.core.request.HttpRequest;
import org.monster.context.core.request.HttpRequestFacade;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 服务者执行器
 *
 * @author Monster
 */
public class ServletExecutor extends LifeCycleTemplate {

    /**
     * 日志器
     */
    private static final Logger logger = Logger.getLogger(ServletExecutor.class.getName());
    /**
     * 请求装饰
     */
    private HttpRequestFacade requestFacade;
    /**
     * 响应装饰
     */
    private HttpResponseFacade responseFacade;

    /**
     * 构造方法
     */
    public ServletExecutor() {
        super();
    }

    /**
     * 构造方法
     *
     * @param servlet 服务者
     */
    public ServletExecutor(HttpServlet servlet) {
        super(servlet);
    }

    /**
     * 设置装饰
     *
     * @param request  请求
     * @param response 响应 响应
     */
    public void setFacade(HttpRequest request, HttpResponse response) {
        requestFacade = new HttpRequestFacade(request);
        responseFacade = new HttpResponseFacade(response);
    }

    /**
     * 执行Serlvet容器不存在的Servlet，服务方法,需先创建
     *
     * @param request  请求
     * @param response 响应 响应
     * @param clazz    类
     * @return http服务者
     */
    public HttpServlet service(HttpRequest request, HttpResponse response,
                               Class<?> clazz) {
        setServlet(ServletFactory.getInstance(clazz));
        setFacade(request, response);
        ServletConfig sc = getServletConfig(clazz);
        Method init = getInitMethod(clazz);
        if (init != null) {
            try {
                init.invoke(getServlet(), sc);
            } catch (IllegalAccessException | IllegalArgumentException
                    | InvocationTargetException ex) {
                logger.log(Level.SEVERE, null, ex);
            }
        }
        try {
            execute(request, getServlet());
        } catch (ServletException | IOException ex) {
            logger.log(Level.SEVERE, null, ex);
        }

        return getServlet();
    }

    /**
     * 服务
     * 执行servlet容器已存在的Serlvet的服务方法
     *
     * @param request  请求
     * @param response 响应
     * @param servlet  http服务者
     * @return http服务者
     */
    public HttpServlet service(HttpRequest request, HttpResponse response,
                               HttpServlet servlet) {
        setServlet(servlet);
        setFacade(request, response);
        try {
            execute(request, servlet);
        } catch (ServletException | IOException ex) {
            logger.log(Level.SEVERE, null, ex);
        }
        return servlet;
    }

    /**
     * 执行
     *
     * @param request 请求
     * @param servlet http服务者
     * @throws ServletException 服务者异常
     * @throws IOException      输入输出异常
     */
    private void execute(HttpRequest request, HttpServlet servlet)
            throws ServletException, IOException {
        String method = request.getMethod();
        String doMethodName = getExecuteMethodName(method);
        Method doMethod = getExecuteMethod(servlet.getClass(), doMethodName);
        if (doMethod != null) {
            try {
                doMethod.invoke(servlet, requestFacade,
                        responseFacade);
            } catch (IllegalAccessException | IllegalArgumentException
                    | InvocationTargetException ex) {
                logger.log(Level.SEVERE, null, ex);
            }
        } else {
            servlet.service(requestFacade,
                    responseFacade);
        }

    }

}
